
#include "ImageHandler.h"
#include "PluginUtility.h"

#include <fbs.h>					//CFbsBitmap
#include <BitmapTransforms.h>		//CBitmapScaler (BitmapTransforms.lib)
#include <ImageConversion.h>		//CImageDecoder (ImageConversion.lib)
#include <eikenv.h>					//CEikonEnv


_LIT8(KJpegMimeType, "image/jpeg");
_LIT8(KGifMimeType, "image/gif");
_LIT8(KPngMimeType, "image/png");


CImageHandler::CImageHandler(CFbsBitmap& aBitmap, MImageHandlerObserver& aObserver)
: CActive(CActive::EPriorityStandard), iBitmap(aBitmap), iObserver(aObserver), iFileExtension(NULL),
iState(ENotInitiated)
{
}

EXPORT_C CImageHandler* CImageHandler::NewLC(CFbsBitmap& aBitmap, MImageHandlerObserver& aObserver)
{
	CImageHandler* self = new (ELeave)CImageHandler(aBitmap, aObserver);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
}

EXPORT_C CImageHandler* CImageHandler::NewL(CFbsBitmap& aBitmap, MImageHandlerObserver& aObserver)
{
	CImageHandler* self = CImageHandler::NewLC(aBitmap, aObserver);
	CleanupStack::Pop(); // self;
	return self;
}

void CImageHandler::ConstructL()
{
	//Reference to connection object
	iConnection = CConnection::Static();

	//Create scaler
	iScaler = CBitmapScaler::NewL();
	
	//Add to scheduler
	CActiveScheduler::Add(this);
}

EXPORT_C CImageHandler::~CImageHandler()
{
	//Delete objects
	DELETE(iDecoder);
	DELETE(iScaler);
	DELETE(iFileExtension);
}

EXPORT_C void CImageHandler::GetAndConvertL(const TDesC& aImageUrl, const TSize& aSize)
{
	//Set size
	iSize = aSize;

	//Calculate file extension
	TInt pos = aImageUrl.LocateReverse('.');
	if (pos == KErrNotFound) User::Leave(KErrArgument);
	
	DELETE(iFileExtension);
	iFileExtension = aImageUrl.Right(aImageUrl.Length() - pos - 1).AllocL();

	//Download image
	iConnection->SetObserver(this);
	iConnection->RequestL(aImageUrl);
}

void CImageHandler::RunL()
{
	switch(iState)
	{
	case EConverting:
		//Image converted
		if (iStatus == KErrNone)
		{
			ScaleL();
		}
		else
		{
			iState = EFailed;
		}
		break;

	case EScaling:
		//Image scaled
		iState = EImageReady;
		break;
	}

	if (iState == EFailed || iState == EImageReady)
	{
		Cancel();
		iObserver.ImageIsReady(iStatus.Int());
	}
	else
	{
		SetActive();
	}
}

void CImageHandler::DoCancel()
{
	//Cancel resizer
	iDecoder->Cancel();
	iScaler->Cancel();
}

TInt CImageHandler::RunError(TInt aError)
{
	//An error has occurred
	iObserver.ImageIsReady(aError);
	
	return aError;
}

void CImageHandler::ConvertL(TDesC8& aImageData)
{
	iState = EConverting;
	SetActive();

	//Create decoder
	iDecoder = CImageDecoder::DataNewL(CEikonEnv::Static()->FsSession(), aImageData, GetMimeType());
	TFrameInfo frameInfo = iDecoder->FrameInfo(0);
	TRect imageSize = frameInfo.iFrameCoordsInPixels;
	iBitmap.Create(imageSize.Size(), EColor4K);

	//Convert image
	iDecoder->Convert(&iStatus, iBitmap);
}

void CImageHandler::ScaleL()
{
	iState = EScaling;

	//Bitmap size
	TSize bitmapSize = iBitmap.SizeInPixels();

	//Check if desired size is > than bitmap size
	if (iSize.iHeight > bitmapSize.iHeight && iSize.iWidth > bitmapSize.iWidth)
	{
		//We finish
		SetRequestStatus(KErrNone);
		return;
	}

	//Scale the bitmap
	iScaler->Scale(&iStatus, iBitmap, iSize);
}

void CImageHandler::SetRequestStatus(TInt aError)
{
	TRequestStatus* temp = &iStatus;
	User::RequestComplete(temp, KErrNone);
}

void CImageHandler::ResponseRequestedL(TDesC8& aResponse)
{
	//Try to convert image
	ConvertL(aResponse);
}

void CImageHandler::ResponseErrorL(TInt aError)
{
	iState = EFailed;
	iObserver.ImageIsReady(aError);
}

const TDesC8& CImageHandler::GetMimeType()
{
	if (iFileExtension->CompareF(_L("gif")) == 0)
	{
		//gif
		return KGifMimeType;
	}
	else if (iFileExtension->CompareF(_L("png")) == 0)
	{
		//png
		return KPngMimeType;
	}
	
	//default: jpg
	return KJpegMimeType;
}